package org.dhbw.oodb.dmlp;

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.persistence.EntityManager;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JProgressBar;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingConstants;

import org.dhbw.oodb.dmlp.jpql.EMFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;

import java.awt.Font;

public class dmlpApp {
	private JLabel lblState;
	private JFrame frame;
	private JTextField tf_times;
	private JCheckBox chckbxJdbcSingleTransaction;
	private JCheckBox chckbxJdbcBulkTransaction;
	private JCheckBox chckbxJdbcBatchE;
	private JCheckBox chckbxJdbcPreparedBatch;
	private JCheckBox chckbxJpaSingleTransaction;
	private JCheckBox chckbxJpaBatchExecution;
	private JLabel lbl_errors;
	private JButton btnStartBenchmarks;
	private JProgressBar progressBar;
	 private Benchmark bench;
	private JTextArea textArea;

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {

		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					dmlpApp window = new dmlpApp();
					window.frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the application.
	 */
	public dmlpApp() {
		initialize();
	}

	/**
	 * Initialize the contents of the frame.
	 */

	private void initialize() {
		initSpringStuff();
		frame = new JFrame();
		frame.setBounds(100, 100, 372, 352);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.getContentPane().setLayout(null);

		chckbxJdbcSingleTransaction = new JCheckBox("JDBC Single Transaction");
		chckbxJdbcSingleTransaction.setFont(new Font("Arial", Font.PLAIN, 11));
		chckbxJdbcSingleTransaction.setBounds(6, 38, 152, 23);
		frame.getContentPane().add(chckbxJdbcSingleTransaction);

		chckbxJdbcBulkTransaction = new JCheckBox("JDBC Bulk Transaction");
		chckbxJdbcBulkTransaction.setFont(new Font("Arial", Font.PLAIN, 11));
		chckbxJdbcBulkTransaction.setBounds(6, 64, 152, 23);
		frame.getContentPane().add(chckbxJdbcBulkTransaction);

		chckbxJdbcBatchE = new JCheckBox("JDBC Batch Execution");
		chckbxJdbcBatchE.setFont(new Font("Arial", Font.PLAIN, 11));
		chckbxJdbcBatchE.setBounds(6, 90, 139, 23);
		frame.getContentPane().add(chckbxJdbcBatchE);

		chckbxJdbcPreparedBatch = new JCheckBox("JDBC Prepared Batch Execution");
		chckbxJdbcPreparedBatch.setFont(new Font("Arial", Font.PLAIN, 11));
		chckbxJdbcPreparedBatch.setBounds(6, 116, 177, 23);
		frame.getContentPane().add(chckbxJdbcPreparedBatch);

		tf_times = new JTextField();
		tf_times.setHorizontalAlignment(SwingConstants.CENTER);
		tf_times.setText("5");
		tf_times.setBounds(72, 11, 43, 20);
		frame.getContentPane().add(tf_times);
		tf_times.setColumns(10);

		JLabel lblBenchmark = new JLabel("Benchmark");
		lblBenchmark.setFont(new Font("Arial", Font.PLAIN, 11));
		lblBenchmark.setBounds(7, 14, 61, 14);
		frame.getContentPane().add(lblBenchmark);

		JLabel lblTimes = new JLabel("times");
		lblTimes.setFont(new Font("Arial", Font.PLAIN, 11));
		lblTimes.setBounds(125, 14, 61, 14);
		frame.getContentPane().add(lblTimes);

		chckbxJpaSingleTransaction = new JCheckBox("JPA Single Transaction");
		chckbxJpaSingleTransaction.setFont(new Font("Arial", Font.PLAIN, 11));
		chckbxJpaSingleTransaction.setBounds(215, 38, 139, 23);
		frame.getContentPane().add(chckbxJpaSingleTransaction);

		chckbxJpaBatchExecution = new JCheckBox("JPA Batch Execution");
		chckbxJpaBatchExecution.setFont(new Font("Arial", Font.PLAIN, 11));
		chckbxJpaBatchExecution.setBounds(215, 64, 139, 23);
		frame.getContentPane().add(chckbxJpaBatchExecution);

		btnStartBenchmarks = new JButton("Start Benchmarks");
		btnStartBenchmarks.setFont(new Font("Arial", Font.PLAIN, 11));
		btnStartBenchmarks.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				setProgress(0);
				setResultText("");
				lbl_errors.setText("");

				boolean[] benchs = new boolean[6];
				if (chckbxJdbcSingleTransaction.isSelected())
					benchs[0] = true;
				else
					benchs[0] = false;
				if (chckbxJdbcBulkTransaction.isSelected())
					benchs[1] = true;
				else
					benchs[1] = false;
				if (chckbxJdbcBatchE.isSelected())
					benchs[2] = true;
				else
					benchs[2] = false;
				if (chckbxJdbcPreparedBatch.isSelected())
					benchs[3] = true;
				else
					benchs[3] = false;
				if (chckbxJpaSingleTransaction.isSelected())
					benchs[4] = true;
				else
					benchs[4] = false;
				if (chckbxJpaBatchExecution.isSelected())
					benchs[5] = true;
				else
					benchs[5] = false;
				int timeseach = 0;
				if (!tf_times.getText().isEmpty()) {
					try {
						timeseach = Integer.parseInt(tf_times.getText());
					} catch (Exception ex) {
						lbl_errors.setText("Please insert a number!");
						return;
					}
				} else {
					lbl_errors.setText("Please insert a number!");
					return;
				}
				enableBenchmarkButton(false);
				performBenchmarks(benchs, timeseach);
			}
		});
		btnStartBenchmarks.setBounds(125, 139, 123, 23);
		frame.getContentPane().add(btnStartBenchmarks);

		lblState = new JLabel("");
		lblState.setHorizontalAlignment(SwingConstants.CENTER);
		lblState.setBounds(126, 163, 123, 14);
		frame.getContentPane().add(lblState);

		lbl_errors = new JLabel("");
		lbl_errors.setForeground(Color.RED);
		lbl_errors.setBounds(167, 14, 161, 14);
		frame.getContentPane().add(lbl_errors);

		progressBar = new JProgressBar();
		progressBar.setBounds(-1, 300, 355, 14);
		frame.getContentPane().add(progressBar);

		textArea = new JTextArea();
		textArea.setColumns(50);
		textArea.setRows(5);
		textArea.setEditable(false);
		textArea.setBounds(6, 180, 340, 117);
		frame.getContentPane().add(textArea);
	}

	public void enableBenchmarkButton(boolean val) {
		btnStartBenchmarks.setEnabled(val);
	}

	public void resetStateLabel() {
		lblState.setText("");
	}

	public void setProgress(int val) {
		this.progressBar.setValue(val);
	}

	public void setResultText(String txt) {
		textArea.setText(txt);
	}

	private void performBenchmarks(boolean[] benchs, int timeseach) {
		BenchmarkPerformer performer = new BenchmarkPerformer(this, benchs,
				timeseach);
		lblState.setText("benchmarking...");
		new Thread(performer).start();
	}
	
	private void initSpringStuff(){
		BeanFactory factory = new XmlBeanFactory(
		          new ClassPathResource("application-context.xml"));
		
		this.bench = (Benchmark)factory.getBean("benchmark");
		
		EntityManager em = EMFactory.getEntityManager();
		this.bench.setEntityManager(em);

	}

	private class BenchmarkPerformer implements Runnable {
		private dmlpApp app;
		boolean[] benchs;
		int timeseach;
		int benchmarkcount = 0;
		int progress = 0;

		public BenchmarkPerformer(dmlpApp app, boolean[] benchs, int timeseach) {
			this.app = app;
			this.benchs = benchs;
			for (boolean b : benchs) {
				if (b)
					benchmarkcount++;
			}
			this.timeseach = timeseach;
		}

		private void updateProgress() {
			progress += (100 / benchmarkcount) / timeseach;
			app.setProgress(progress);
		}

		public void run() {
			progress = 0;
			long sst = 0;
			long sct = 0;
			long sb = 0;
			long sbp = 0;
			long jst = 0;
			long jbt = 0;

			 if(benchs[0]){
			 for(int x=0;x<timeseach;x++){
			 System.out.println("Starting benchmark using SimpleJdbcTemplate.update single Transaction");
			 bench.BenchmarkSpringSingleTransaction(1000);
			 System.out.println("done in "+bench.SNTJDBC/1000 +
			 " seconds ("+bench.SNTJDBC+" milliseconds)");
			
			 sst+=+bench.SNTJDBC/1000;
			 updateProgress();
			 }
			 }
			 if(benchs[1]){
			 for(int x=0;x<timeseach;x++){
			 System.out.println("Starting benchmark using SimpleJdbcTemplate.update bulk Transaction");
			 bench.BenchmarkSpringCustomTransaction(1000);
			 System.out.println("done in "+bench.SNTJDBC/1000 +
			 " seconds ("+bench.SNTJDBC+" milliseconds)");
			
			 sct+=+bench.SNTJDBC/1000;
			 updateProgress();
			 }
			 }
			 if(benchs[2]){
			 for(int x=0;x<timeseach;x++){
			 System.out.println("Starting benchmark using SimpleJdbcTemplate.batch");
			 bench.BenchmarkSpringBatch(5000);
			 System.out.println("done in "+bench.SNTJDBC/1000 +
			 " seconds ("+bench.SNTJDBC+" milliseconds)");
			
			 sb+=+bench.SNTJDBC/1000;
			 updateProgress();
			 }
			 }
			 if(benchs[3]){
			 for(int x=0;x<timeseach;x++){
			 System.out.println("Starting benchmark using SimpleJdbcTemplate.batch with prepared statement");
			 bench.BenchmarkSpringPreparedBatch(5000);
			 System.out.println("done in "+bench.SNTJDBC/1000 +
			 " seconds ("+bench.SNTJDBC+" milliseconds)");
			
			 sbp+=+bench.SNTJDBC/1000;
			 updateProgress();
			 }
			 }
			 if(benchs[4]){
			 for(int x=0;x<timeseach;x++){
			 System.out.println("Starting benchmark using JPA with single Transaction");
			 bench.BenchmarkJPASingleTransaction(1000);
			 System.out.println("done in "+bench.SNTJDBC/1000 +
			 " seconds ("+bench.SNTJDBC+" milliseconds)");
			
			 jst+=+bench.SNTJDBC/1000;
			 updateProgress();
			 }
			 }
			 if(benchs[5]){
			 for(int x=0;x<timeseach;x++){
			 System.out.println("Starting benchmark using JPA with bulk Transaction");
			 bench.BenchmarkJPACustomTransaction(5000);
			 System.out.println("done in "+bench.SNTJDBC/1000 +
			 " seconds ("+bench.SNTJDBC+" milliseconds)");
			
			 jbt+=+bench.SNTJDBC/1000;
			 updateProgress();
			 }
			 }
			
			String result = "Benchmarkresult: \n";
			if (benchs[0])
				result += "Spring JDBC Single Transaction AVG:" + sst / timeseach + "sec\n";
			if (benchs[1])
				result += "Spring JDBC Bulk Transaction AVG:" + sct / timeseach + "sec\n";
			if (benchs[2])
				result += "Spring JDBC Batch Execution AVG:" + sb / timeseach + "sec\n";
			if (benchs[3])
				result += "Spring JDBC Prepared Batch Execution AVG:" + sbp / timeseach + "sec\n";
			if (benchs[4])
				result += "JPA Single Transaction AVG:" + jst / timeseach + "sec\n";
			if (benchs[5])
				result += "JPA Batch Exection AVG:" + jbt / timeseach+"sec";
			
			System.out.println(result);			
			app.setResultText(result);

			app.enableBenchmarkButton(true);
			app.resetStateLabel();
		}
	}
}
